package com.xframe.xdal.core.model;

import com.xframe.xdal.core.constant.DalConstants;
import com.xframe.xdal.core.constant.SqlBuilderConstants;
import com.xframe.xdal.core.model.mapping.IColumnMapping;
import com.xframe.xdal.core.model.mapping.ITableInfo;
import com.xframe.xdal.core.model.sqlbuilder.BuilderContext;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * 功能描述: 排序对象集合
 *
 * @author xufeng
 * @version 1.0
 * @date 2022-09-26
 */
public class DbSortCollection {
    /**
     * 排序对象
     */
    private Set<DbSort> dbSorts = new TreeSet<>();

    private Set<DbSort> mainDbSorts = null;
    private Set<DbSort> chDbSorts = null;


    public Set<DbSort> getDbSorts(){
        return this.dbSorts;
    }
    /**
     * 添加排序对象
     *
     * @param dbSort 排序对象
     */
    public void add(DbSort dbSort) {
        dbSort.setOrderNo(dbSorts.size() + 1);
        dbSorts.add(dbSort);
    }

    public void remove(DbSort dbSort){
        dbSorts.remove(dbSort);
    }

    /**
     * 批量添加排序对象
     *
     * @param dbSortArray 排序对象
     */
    public void addArray(DbSort[] dbSortArray) {
        if (dbSortArray != null) {
            for (int i = 0; i < dbSortArray.length; i++) {
                dbSortArray[i].setOrderNo(dbSorts.size() + 1);
                dbSorts.add(dbSortArray[i]);
            }
        }
    }

    public DbSortCollection() {
    }

    public DbSortCollection(DbSort[] dbSortArray) {
        addArray(dbSortArray);
    }

    /**
     * 根据名称添加排序
     *
     * @param name    排序名称
     * @param sortDir 排序类型对象
     */
    public void add(String name, DbSort.SortDir sortDir) {
        dbSorts.add(new DbSort(name, sortDir));
    }

    /**
     * 排序集合大小
     *
     * @return int
     */
    public int size() {
        return this.dbSorts.size();
    }

    /**
     * 排序集合是否为空
     *
     * @return true 为空 false 为非空
     */
    public boolean isEmpty() {
        return this.dbSorts.size() == 0;
    }

    /**
     * 构建sql 语句order by 后的 排序sql 语句 通常情况下
     *
     * @return sql 语句
     */
    public String getOrderBySql(BuilderContext context,ITableInfo tableInfo,
                                Map<String,ITableInfo> refTable,
                                String colPlaceholder) {
        StringBuilder orderByBuilder = new StringBuilder();
        int index = 0;
        for (DbSort dbSort: dbSorts) {
            boolean isAddString = false;
            if(dbSort.isAttrPath()){
                String[] paths = dbSort.getSortColName().split("\\" + SqlBuilderConstants.SP);
                if(refTable.containsKey(paths[0])){
                    ITableInfo refTableInfo = refTable.get(paths[0]);
                    orderByBuilder.append(buildHelp(context,colPlaceholder,refTableInfo,paths[0],paths[1],dbSort));
                    isAddString = true;
                }
            }else {
                orderByBuilder.append(buildHelp(context,colPlaceholder,tableInfo,SqlBuilderConstants.MAINTABELNAME,dbSort.getSortColName(),dbSort));
                isAddString = true;
            }
            if (index + 1 < dbSorts.size() && isAddString) {
                orderByBuilder.append(DalConstants.SQL_SEPARATION);
            }
            index++;
        }
        return orderByBuilder.toString();
    }


    /**
     * 构建sql 语句order by 如果不存在ID排序则插入ID排序到第一位，否则修改顺序到第一位
     *
     * @return sql 语句
     */
    public String getOrderByComplicatedSql(BuilderContext context,ITableInfo tableInfo,
                                Map<String,ITableInfo> refTable,
                                String colPlaceholder){

        DbSort sort = findPkSort(tableInfo);
        if(sort == null){
            // 没有主键则不支持排序
            this.dbSorts.clear();
            return "";
        }
        this.dbSorts.remove(sort);

        this.dbSorts.add(sort);

        return getOrderBySql(context,tableInfo,refTable,colPlaceholder);

    }






    /**
     * 分割排序,将主表的排序和子表的排序分成两段
     *
     */
    public void split(ITableInfo tableInfo){
        this.mainDbSorts = new TreeSet<>();
        this.chDbSorts = new TreeSet<>();

        for (DbSort dbSort: dbSorts) {
            if(dbSort.isAttrPath()){
                chDbSorts.add(dbSort);
            }else {
                mainDbSorts.add(dbSort);
            }
        }
        if(this.chDbSorts != null && this.chDbSorts.size() > 0){
            // 末尾添加一个ID排序
            DbSort dbSort = findPkSort(tableInfo);
            if(dbSort == null){
                this.chDbSorts.clear();
            }else {
                dbSort.setOrderNo(99999);
                this.chDbSorts.add(dbSort);
            }
        }
    }

    public String getPageOrderSql(BuilderContext context,ITableInfo tableInfo,
                                       String colPlaceholder){
        StringBuilder orderByBuilder = new StringBuilder();
        int index = 0;

        IColumnMapping mapping = tableInfo.findPkFirst();
        if(mapping == null){
            return "";
        }
        boolean isPk = false;
        boolean hasVal = false;
        for (DbSort dbSort: this.mainDbSorts) {
            if(!dbSort.isAttrPath()){
                orderByBuilder.append(buildHelp(context,colPlaceholder,tableInfo,SqlBuilderConstants.MAINTABELNAME,dbSort.getSortColName(),dbSort));
                hasVal = true;
                if (index + 1 < this.mainDbSorts.size()) {
                    orderByBuilder.append(DalConstants.SQL_SEPARATION);
                }
                if(!isPk && dbSort.getFieldName().equals(mapping.getFieldName())){
                    isPk = true;
                }
            }
            index++;
        }
//        if(!isPk){
//            DbSort dbSortTmp = new DbSort(mapping.getFieldName());
//            if(hasVal) {
//                orderByBuilder.insert(0, buildHelp(context, colPlaceholder, tableInfo,
//                        SqlBuilderConstants.MAINTABELNAME, dbSortTmp.getSortColName(), dbSortTmp) + ",");
//            }else {
//                orderByBuilder.insert(0, buildHelp(context, colPlaceholder, tableInfo,
//                        SqlBuilderConstants.MAINTABELNAME, dbSortTmp.getSortColName(), dbSortTmp));
//            }
//        }
//        if(orderByBuilder.length() > 0){
//            orderByBuilder.insert(0,DalConstants.SQL_ORDER_BY);
//        }
        return orderByBuilder.toString();

    }


    public String getMainTableOrderSql(BuilderContext context,ITableInfo tableInfo,
                                     String colPlaceholder){
        StringBuilder orderByBuilder = new StringBuilder();
        int index = 0;

        IColumnMapping mapping = tableInfo.findPkFirst();
        if(mapping == null){
            return "";
        }
        boolean isPk = false;
        boolean hasVal = false;
        for (DbSort dbSort: this.mainDbSorts) {
            if(!dbSort.isAttrPath()){
                orderByBuilder.append(buildHelp(context,colPlaceholder,tableInfo,SqlBuilderConstants.MAINTABELNAME,dbSort.getSortColName(),dbSort));
                hasVal = true;
                if (index + 1 < this.mainDbSorts.size()) {
                    orderByBuilder.append(DalConstants.SQL_SEPARATION);
                }
                if(!isPk && dbSort.getFieldName().equals(mapping.getFieldName())){
                    isPk = true;
                }
            }
            index++;
        }
        if(!isPk){
            DbSort dbSortTmp = new DbSort(mapping.getFieldName());
            if(hasVal) {
                orderByBuilder.insert(0, buildHelp(context, colPlaceholder, tableInfo,
                        SqlBuilderConstants.MAINTABELNAME, dbSortTmp.getSortColName(), dbSortTmp) + ",");
            }else {
                orderByBuilder.insert(0, buildHelp(context, colPlaceholder, tableInfo,
                        SqlBuilderConstants.MAINTABELNAME, dbSortTmp.getSortColName(), dbSortTmp));
            }
        }
        if(orderByBuilder.length() > 0){
            orderByBuilder.insert(0,DalConstants.SQL_ORDER_BY);
        }
        return orderByBuilder.toString();

    }


    public String getSonTableOrderSql(BuilderContext context,ITableInfo tableInfo,
                                    Map<String,ITableInfo> refTable,
                                    String colPlaceholder,boolean isAddOrderBy){
        StringBuilder orderByBuilder = new StringBuilder();
        int index = 0;
        for (DbSort dbSort: this.chDbSorts) {
            boolean isAddString = false;
            if(dbSort.isAttrPath()){
                String[] paths = dbSort.getSortColName().split("\\" + SqlBuilderConstants.SP);
                if(refTable.containsKey(paths[0])){
                    ITableInfo refTableInfo = refTable.get(paths[0]);
                    orderByBuilder.append(buildHelp(context,colPlaceholder,refTableInfo,paths[0],paths[1],dbSort));
                    isAddString = true;
                }
            }else {
                orderByBuilder.append(buildHelp(context,colPlaceholder,tableInfo,SqlBuilderConstants.MAINTABELNAME,dbSort.getSortColName(),dbSort));
                isAddString = true;
            }
            if(isAddOrderBy) {
                if (index + 1 < this.chDbSorts.size() && isAddString) {
                    orderByBuilder.append(DalConstants.SQL_SEPARATION);
                }
            }
            index++;
        }
        if(orderByBuilder.length() > 0){
            orderByBuilder.insert(0,DalConstants.SQL_ORDER_BY);
        }
        return orderByBuilder.toString();
    }



    /**
     * 查找PK字段
     *
     * @return sql 语句
     */
    private DbSort findPkSort(ITableInfo tableInfo){
        IColumnMapping columnMapping = tableInfo.findPkFirst();
        if(columnMapping == null){
            // 没有主键则不支持排序
            //this.dbSorts.clear();
            return null;
        }

        for (DbSort dbSort:this.getDbSorts()) {
            if(dbSort.getFieldName().equals(columnMapping.getFieldName())){
                dbSort.setOrderNo(0);
                return dbSort;
            }
        }
        return new DbSort(columnMapping.getFieldName(), DbSort.SortDir.ASC,0);

    }


    private static String buildHelp(BuilderContext context, String placeholder, ITableInfo refTableInfo, String asName,
                                    String attrName, DbSort dbSort){
        IColumnMapping columnMapping = refTableInfo.findOneByFieldName(attrName);
        if(columnMapping == null){
            return "";
        }
        return placeholder + asName + placeholder + SqlBuilderConstants.SP +
                placeholder + context.getNameConvert().toName(columnMapping.getName()) + placeholder + " " + dbSort.getSortDir();

    }


    public void SetSearchSourceBuilderSorts(SearchSourceBuilder searchSourceBuilder,ITableInfo tableInfo){
        if(this.dbSorts != null && this.dbSorts.size() > 0){

            this.dbSorts.forEach(dbSort -> {
                String sortName = dbSort.getFieldName();

                IColumnMapping columnMapping = tableInfo.findOneByFieldName(dbSort.getFieldName());
                if(columnMapping != null && columnMapping.getDataType().equals(String.class)){
                    sortName = sortName + ".keyword";
                }
                searchSourceBuilder.sort(sortName, dbSort.getSortDir() == DbSort.SortDir.ASC ? SortOrder.ASC:SortOrder.DESC);
            });
        }
    }

}
